Skip to content

docs(P-012): record loop-invariant-call mining packet as a research seed - #329

Merged
PhysShell merged 2 commits into
mainfrom
claude/dotnet-optimization-experiments-6147se
Aug 10, 2026
Merged

docs(P-012): record loop-invariant-call mining packet as a research seed#329
PhysShell merged 2 commits into
mainfrom
claude/dotnet-optimization-experiments-6147se

Conversation

@PhysShell

@PhysShell PhysShell commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Что и зачем

Добавляет в P-012 одну секцию внутри материала stage 2 — схему майнинга для кандидатов «инвариантный вызов внутри цикла». Это описание измерения, а не архитектура, и три вещи стоит подчеркнуть прямо:

  1. Это не планирование чекера. Первая строка секции — Research seed only; does not schedule or specify a checker. Никакого дизайна правила, атрибутов, вайтлистов приёмников, решётки или fix-арма внутрь не протащено — всё это выводы из чисел, которых пока нет.
  2. Три оси сохраняются независимо именно ради измерения узкого места. «Можно ли вынести вызов» — не одно свойство, а три: неизменность входов, повторяемость вызова и легальность самого переноса. Плоская метка убила бы единственный интересный результат — какая ось съедает покрытие дешёвой версии. Случаи «входы доказаны, повторяемость доказана, размещение неизвестно» и «входы доказаны, повторяемость неизвестна, размещение доказано» при схлопывании оба станут UNKNOWN, и продуктовый вопрос перестанет быть отвечаемым из данных.
  3. Это следствие уже смёрженного измерения. docs/notes/invariant-cost-static-vs-runtime.md (PR docs(notes): measured .NET optimization limits and GC/LOH observability #327) намерил разброс 1.0×–1092× на четырёх выбранных вручную формах и закончился тем, что честный первый шаг — майнинг, а не правило. Секция фиксирует этот шаг, и только его.

Содержательно: 16 наблюдаемых полей; три оси меток (input_stability / call_repeatability / placement_safety); производный бакет, который никогда не записывается вместо трёх исходных и выводится упорядоченным тотальным правилом.

Два поля — call_control_context и call_reachability_per_iteration — существуют потому, что наличие control transfer само по себе ничего не различает: var x = F(); if (c) break; и if (c) break; var x = F(); дают одинаковый флаг и совершенно разную placement-историю. Скан не обязан эту разницу разрешать, но не должен её потерять. call_control_contextмножество, а не одно значение, потому что его значения реально пересекаются (c && F() одновременно conditional и short-circuit-operand).

Два guard-абзаца закрывают дверь перед тем, чтобы список колонок через полгода превратился в предикат вида if immutable_receiver and not contains_throw: report(): ни одно поле по отдельности, включая иммутабельность приёмника, не является доказательством того, что вынос сохраняет семантику, и проход обязан сохранять unknown, а не выводить безопасность из отсутствия распознанной опасности.

Тип изменения

  • feat — новая возможность
  • fix — исправление бага
  • docs — документация
  • refactor / chore / test / ci — без изменения поведения

Как проверено

Поведения нет — дифф целиком документационный, вставка в один файл, поэтому тесты репозитория не применимы и не гонялись.

Проверено то, что относится к самому изменению:

  • Чистое добавление в исходном коммите: +78 / -0, один файл, ноль удалённых строк.
  • Границы: Status, зависимости, non-goals, docs/ROADMAP.md и индекс предложений не тронуты; секция вставлена после материала stage 2 / detectability, перед ## Open questions.
  • Скоуп проверен механически: в диффе ноль вхождений OwnPure, ImmutableArray, lattice, autofix, whitelist, LLVM, speculatable.
  • Схема непротиворечива: 19 строк таблиц = 19 идентификаторов, композитных полей не осталось.
  • markdownlint: MD028 = 0. Остающиеся MD013/line-length на строках таблиц соответствуют уже существующим таблицам этого файла (они идут до 108 символов), то есть это его конвенция, а не привнесённое здесь.
  • Ссылки: обе относительные ссылки в файле резолвятся.

Связанные issue

Нет, и намеренно. Секция ничего не планирует в работу — по дисциплине research-landscape-2026.md заметки и предложения фиксируют, планирует ROADMAP. Заводить issue под research seed значило бы создать вторую поверхность статуса для работы, которая сознательно не в очереди.

Чеклист

  • изменение покрыто тестом/селфтестом (или объяснено, почему нет) — тестов нет: дифф документационный, проверяемого поведения не вводит
  • README/docs обновлены при необходимости — изменение целиком документационное; ROADMAP.md и индекс предложений намеренно не трогались, чтобы research seed не выглядел запланированной работой
  • коммиты в conventional-commit стиле (feat:, fix:, docs: …)

Про упоминание промышленного прецедента: в тексте одна фраза о том, что компиляторы держат repeatability и placement legality разными атрибутами — как подтверждение декомпозиции, с явной оговоркой «не готовое соответствие для C#». Имён атрибутов и таблицы соответствия нет намеренно.

Имена значений осей записаны прозой через дефис (cheap-proven), а не как идентификаторы: это предложение о том, что измерять, а не wire-схема будущего сканера — машинные имена должен определить его собственный контракт.

…ch seed

The merged invariant-cost note measured a 1.0x-1092x spread over four
hand-picked shapes and closed by saying the honest first step is mining, not a
rule. This records what that scan should collect, so the measurement design does
not evaporate — it survives even if a future checker turns out to be a
completely different thing, because it describes an observation, not an
architecture.

The packet keeps three independent label axes -- input stability, call
repeatability, placement safety -- with the flat bucket derived from them and
never recorded instead of them. Collapsing early is what would waste the scan:
inputs-proven/repeatability-proven/placement-unknown and
inputs-proven/repeatability-unknown/placement-proven both flatten to UNKNOWN,
and the product question of which axis is the bottleneck stops being answerable
from the data.

Two fields exist specifically because the presence of a control transfer is not
discriminating on its own: `var x = F(); if (c) break;` and `if (c) break; var x
= F();` record identical control-transfer syntax and have entirely different
placement stories, so call_control_context and call_reachability_per_iteration
keep a difference the scan is not required to resolve but must not lose.

Two guards are stated in the text because a column list invites being turned
into a predicate: no single field, receiver immutability included, is evidence
that hoisting preserves semantics, and the pass must preserve unknown rather
than infer safety from the absence of a recognised hazard.

Pure addition inside the stage-2 material, marked "Research seed only; does not
schedule or specify a checker." Status, dependencies, non-goals, the ROADMAP and
the proposal index are untouched; no issue is filed; no attribute, receiver
whitelist, lattice or fix-arm design is introduced -- those are conclusions from
numbers that do not exist yet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PbyzyVi7fibuSKLweuXgea
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The proposal adds a stage-2 syntactic scan for calls inside loops. It defines candidate metadata, independent stability, repeatability, and placement labels, derived classification buckets, and safeguards against treating observations as a loop-hoisting specification.

Changes

Loop-call mining

Layer / File(s) Summary
Define loop-call candidate classification
docs/proposals/P-012-bug-corpus-mining.md
Documents candidate observations, control-flow and reachability metadata, independent labels, derived buckets, and unknown-state handling for repeated loop-invariant-call candidates.

Estimated code review effort: 1 (Trivial) | ~3 minutes

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the documentation change and its research-seed purpose.
Description check ✅ Passed The description fills all template sections and explains the documentation scope, validation, testing rationale, and intentionally absent issue.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/dotnet-optimization-experiments-6147se

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/proposals/P-012-bug-corpus-mining.md`:
- Line 221: Remove the standalone blank blockquote line in the quoted section of
P-012, keeping the surrounding guards as one continuous blockquote or list so
markdownlint MD028 passes.
- Around line 174-180: Update the observation schema table so its field count
matches the documented 15-field objective: explicitly define capture_count and
capture_types as one composite field, or revise the declared total to 16 if they
remain separate fields. Ensure the schema description and listed identifiers
consistently communicate the chosen representation.
- Around line 206-208: Define explicit deterministic precedence rules for
deriving the bucket from the three source labels, including conflicts among
multiple reasoning-required states and any disproven state combined with a
reasoning-required state. Update the derived-bucket specification near
CHEAP_PROVABLE so every source-label tuple maps to exactly one bucket without
recording the derived value as a replacement for the source labels.
- Line 189: Clarify the call_control_context schema in the proposal by making it
a set of applicable context values, so overlapping classifications such as
conditional, short-circuit-operand, and nested-lambda-or-local-function are
retained. If it must remain single-valued, define explicit precedence that
preserves all relevant facts.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 230a5ec9-bebf-49d6-9650-d33a57da1a54

📥 Commits

Reviewing files that changed from the base of the PR and between cc267cb and d84adf5.

📒 Files selected for processing (1)
  • docs/proposals/P-012-bug-corpus-mining.md

Comment thread docs/proposals/P-012-bug-corpus-mining.md Outdated
Comment thread docs/proposals/P-012-bug-corpus-mining.md Outdated
Comment thread docs/proposals/P-012-bug-corpus-mining.md Outdated
Comment thread docs/proposals/P-012-bug-corpus-mining.md Outdated
Four review findings, all checked against the text and all valid; none changes
what the packet says, each removes a way to read it two ways.

capture_count and capture_types shared one table row, so the table had one fewer
row than it had identifiers and a miner could reasonably emit either shape. They
are now one row each: 19 rows, 19 identifiers, no composite left implicit.

call_control_context was written as a single value while its values genuinely
overlap -- `c && F()` is both conditional and short-circuit-operand, and a call
in a lambda under an if is also nested-lambda-or-local-function. Forcing one
value would discard exactly the distinctions the field exists to keep, so it is
now explicitly a set, with the overlap spelled out.

The derived bucket named five outcomes without saying how a label tuple maps to
one, and two tuples matched two buckets: needs-effect-reasoning together with
needs-cfg-reasoning, and disproven together with any reasoning-required axis. It
now derives by an ordered, total rule. A settled negative takes precedence over
an open axis; the order of the two reasoning rungs is a reporting convention
rather than a claim about which reasoning dominates, and it costs nothing
because the three axis labels are always kept, so a candidate needing both is
recoverable from the data whichever bucket it rolls into.

The two guards were two blockquotes separated by a blank line, which trips
markdownlint MD028; they are one blockquote with two bullets now. Verified:
MD028 count is 0. The MD013 line-length reports that remain on the new table
rows match this document's existing tables, which already run past 100
characters, so they are its convention and are left alone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PbyzyVi7fibuSKLweuXgea
@PhysShell
PhysShell merged commit f3d3e86 into main Aug 10, 2026
42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants